Skip to content

Unify StubLinker stub memory management with JIT code allocator - #131903

Merged
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs
Aug 7, 2026
Merged

Unify StubLinker stub memory management with JIT code allocator#131903
jkotas merged 17 commits into
mainfrom
copilot/unify-memory-management-for-stubs

Conversation

Copilot AI commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

StubLinker-generated stubs used a dedicated LoaderAllocator::m_pStubHeap, separate from the executable memory infrastructure shared by JITed code and other stub kinds. This PR unifies the two paths.

  • LoaderAllocator: removed m_pStubHeap and its init/terminate/DAC/size-reporting plumbing.
  • StubLinker/Stub: StubLinker::Link and Stub::NewStub now take a LoaderAllocator* instead of a LoaderHeap*, allocating stub memory through ExecutionManager::GetEEJitManager()->AllocCodeFragmentBlock.
  • StubCodeBlockKind: added STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK to distinguish these stubs in the code-fragment allocator.
  • StubLinkStubManager: removed its own range list; RangeSectionStubManager now recognizes the new stub kinds and forwards stub identification/tracing to StubLinkStubManager (mirroring the existing pattern for jump stubs and call-counting stubs).
  • DAC/SOS: updated datadescriptor.inc and debug/daccess/request.cpp to drop the removed stub heap field.
  • Call sites: updated stubcache.cpp, comdelegate.cpp, prestub.cpp, assembly.cpp, appdomain.hpp/.inl, and class.h to pass LoaderAllocator* instead of a stub LoaderHeap*.
// Before
Stub *Link(LoaderHeap *heap, DWORD flags, const char *stubType);

// After
Stub *Link(LoaderAllocator *pLoaderAllocator, DWORD flags, const char *stubType);

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors CoreCLR stub generation so StubLinker-produced stubs (including shuffle thunks) allocate executable memory via the JIT’s code-fragment allocator rather than a dedicated LoaderAllocator::m_pStubHeap, and updates stub identification/tracing plus DAC descriptors accordingly.

Changes:

  • Reworks StubLinker::Link / Stub::NewStub to allocate stub memory via EEJitManager::AllocCodeFragmentBlock, keyed by new StubCodeBlockKind values.
  • Removes LoaderAllocator’s dedicated stub heap field/plumbing and updates call sites to pass LoaderAllocator*.
  • Updates stub manager routing (RangeSectionStubManagerStubLinkStubManager) and cDAC descriptors for the removed stub heap field.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/coreclr/vm/stubmgr.h Removes StubLinkStubManager’s range list plumbing (moves identification to range-section kind).
src/coreclr/vm/stubmgr.cpp Routes STUBLINK/SHUFFLE kinds through RangeSectionStubManager and forwards tracing to StubLinkStubManager.
src/coreclr/vm/stublink.h Changes StubLinker::Link to take LoaderAllocator*; updates Stub::NewStub signature.
src/coreclr/vm/stublink.cpp Allocates stub memory using AllocCodeFragmentBlock and tags with new stub kinds.
src/coreclr/vm/stubcache.h Updates stub cache to retain a LoaderAllocator* instead of a LoaderHeap*.
src/coreclr/vm/stubcache.cpp Passes LoaderAllocator* through to StubLinker::Link.
src/coreclr/vm/prestub.cpp Updates stub linker call sites to pass LoaderAllocator*.
src/coreclr/vm/loaderallocator.hpp Removes m_pStubHeap and its accessor; updates cDAC offsets accordingly.
src/coreclr/vm/loaderallocator.cpp Removes stub heap initialization/termination/enumeration/size accounting; adjusts shuffle thunk cache initialization.
src/coreclr/vm/datadescriptor/datadescriptor.inc Drops the LoaderAllocator.StubHeap cDAC field.
src/coreclr/vm/comdelegate.h Updates ShuffleThunkCache to use LoaderAllocator*.
src/coreclr/vm/comdelegate.cpp Updates global shuffle thunk cache init; changes DelegateEEClass::GetStubHeap to return LoaderAllocator*.
src/coreclr/vm/codeman.h Adds STUB_CODE_BLOCK_STUBLINK and STUB_CODE_BLOCK_SHUFFLE_THUNK kinds and string mappings.
src/coreclr/vm/class.h Updates DelegateEEClass::GetStubHeap return type to LoaderAllocator*.
src/coreclr/vm/assembly.hpp Removes Assembly::GetStubHeap declaration.
src/coreclr/vm/assembly.cpp Removes Assembly::GetStubHeap implementation.
src/coreclr/vm/appdomain.hpp Removes AppDomain::GetStubHeap declaration.
src/coreclr/vm/appdomain.inl Removes AppDomain::GetStubHeap inline implementation.
src/coreclr/debug/daccess/request.cpp Updates DAC exposure of “stub heap” data and heap-name list for loader allocator heap enumeration.

Comment thread src/coreclr/debug/daccess/request.cpp
Comment thread src/coreclr/vm/comdelegate.cpp Outdated
Comment thread src/coreclr/vm/class.h Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

Comment thread src/coreclr/vm/loaderallocator.cpp
Comment thread src/coreclr/debug/daccess/request.cpp Outdated
Comment thread src/coreclr/vm/codeman.h Outdated
Comment thread src/coreclr/vm/codeman.h Outdated
…EAP_*

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 5, 2026 21:27
Copilot AI requested a review from jkotas August 5, 2026 21:27
Comment thread src/coreclr/vm/stublink.cpp Outdated
Comment thread src/coreclr/vm/stublink.cpp Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

src/coreclr/vm/comdelegate.cpp:824

  • The comment says this method returns a LoaderHeap, but it now returns a LoaderAllocator*. Updating the comment avoids misleading future readers about what lifetime guarantee is being relied on here.
// We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
LoaderAllocator *DelegateEEClass::GetStubHeap()

src/coreclr/vm/class.h:1925

  • This comment still refers to returning a LoaderHeap, but the method now returns a LoaderAllocator*. Keeping the comment accurate is important since this is the declaration most readers will see.
    // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer
    LoaderAllocator *GetStubHeap();

src/coreclr/debug/daccess/request.cpp:3686

  • LoaderAllocatorLoaderHeapNames is out of sync with GetLoaderAllocatorHeaps(): the names array includes both "ExecutableStubHeap" and "ExecutableHeap", but GetLoaderAllocatorHeaps() now only returns one executable heap pointer at that slot. This makes GetLoaderAllocatorHeapNames() report a different count/order than the returned heap addresses, which can confuse SOS/DAC consumers.
    "ExecutableStubHeap",
    "ExecutableHeap",
    "FixupPrecodeHeap",

Comment thread src/coreclr/vm/datadescriptor/datadescriptor.inc
Comment thread src/coreclr/vm/stubmgr.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 5, 2026 21:42
Comment thread src/coreclr/vm/appdomain.hpp Outdated
@jkotas
jkotas marked this pull request as ready for review August 6, 2026 14:23
@jkotas
jkotas requested review from BrzVlad and janvorli as code owners August 6, 2026 14:23
@jkotas
jkotas requested a review from rcj1 August 6, 2026 14:23
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 6, 2026 14:33
Copilot AI requested a review from jkotas August 6, 2026 14:35
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/coreclr/vm/eventtrace.cpp:3626

  • StubInitialized now reports a hard-coded helper size of 1 byte, which looks like a placeholder after removing Stub::RecoverStubAndSize. This will produce incorrect ETW MethodLoad events (size is part of the payload) for write-barrier helpers and any other helpers that call into this path.

Consider restoring a real size calculation (e.g., change StubInitialized to take a size parameter and pass the known helper size from the call sites), or otherwise derive the helper size from the allocation metadata instead of a constant.

            DWORD dwHelperSize = 1;

Copilot AI review requested due to automatic review settings August 6, 2026 14:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/coreclr/vm/stubcache.h:47

  • StubCacheBase allows a default NULL loader allocator, but StubLinker::Link ultimately calls EEJitManager::AllocCodeFragmentBlock, which has a PRECONDITION(pLoaderAllocator != NULL). This makes the API foot-gun: any future (or accidental) default construction would crash/assert. Make the requirement explicit by removing the default argument (and optionally assert non-null in the constructor).
    StubCacheBase(LoaderAllocator *pLoaderAllocator = NULL);

src/coreclr/vm/eventtrace.cpp:3627

  • dwHelperSize is now hardcoded to 1, so ETW MethodLoadVerbose will report every helper stub as a 1-byte method. That’s very likely misleading for diagnostics tooling that expects size/range information. If the size is no longer recoverable from a Stub header, consider plumbing the size from the call site (e.g., write-barrier helper generation knows sizes) or adding a helper to derive the real stub/code-fragment size from allocation metadata; if neither is possible, please add an explicit comment explaining why reporting size=1 is acceptable.
            DWORD dwHelperSize = 1;
            ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);

Comment thread src/coreclr/vm/comdelegate.h Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/coreclr/vm/codeman.h:131

  • GetStubCodeBlockKindString no longer returns accurate names for several stub kinds: STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE both return "MethodCallThunk", and STUB_CODE_BLOCK_STUBPRECODE is not handled at all (falls through to "Unknown"). This breaks perfmap/event naming for these stubs and makes it harder to diagnose stub allocations.
    case STUB_CODE_BLOCK_JUMPSTUB:
        return "JumpStub";
    case STUB_CODE_BLOCK_DYNAMICHELPER:
        return "MethodCallThunk";
    case STUB_CODE_BLOCK_FIXUPPRECODE:
        return "MethodCallThunk";
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH

src/coreclr/vm/eventtrace.cpp:3628

  • StubInitialized now reports a hardcoded helper size of 1 byte. This value is emitted into FireEtwMethodLoadVerbose_V1 and will produce incorrect ETW method-load metadata for helper stubs (notably the write barrier helpers reported from threads.cpp). The size should either be computed from the actual stub allocation or passed in by the caller that knows the exact size.
        if(ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
                                        TRACE_LEVEL_INFORMATION,
                                        CLR_JIT_KEYWORD))
        {
            DWORD dwHelperSize = 1;
            ETW::MethodLog::SendHelperEvent(ullHelperStartAddress, dwHelperSize, pHelperName);
        }

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs:107

  • StubKind was extended with WrapperStub and ShuffleThunk, but GetStubKind(StubKind stubKind) (later in this file) does not map these new values to any CodeKind, so these stubs will be reported as CodeKind.Unknown via GetCodeKind when walking range-list stubs. Either map them to an existing CodeKind (e.g., MethodCallThunk) or extend CodeKind if tools need to distinguish them.

Comment thread src/coreclr/vm/eventtrace.cpp Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 44 out of 44 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/coreclr/vm/stubmgr.cpp:1265

  • StubLinkStubManager::CheckIsStub_Internal now unconditionally returns FALSE. Since this type still exists as a StubManager implementation, this makes its stub-identification behavior incorrect and brittle if any caller ever queries this manager directly (or if stub-manager ordering changes). It can safely determine membership by checking the code-fragment kind via RangeSectionStubManager::GetStubKind (the same mechanism used by DoTraceStub/TraceManager).

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 46 out of 46 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/coreclr/vm/codeman.h:130

  • GetStubCodeBlockKindString returns "MethodCallThunk" for STUB_CODE_BLOCK_DYNAMICHELPER and STUB_CODE_BLOCK_FIXUPPRECODE, and STUB_CODE_BLOCK_STUBPRECODE isn't handled at all. This makes perfmap stub-block names misleading and can cause StubPrecode blocks to show up as "Unknown".
    case STUB_CODE_BLOCK_DYNAMICHELPER:
        return "MethodCallThunk";
    case STUB_CODE_BLOCK_FIXUPPRECODE:
        return "MethodCallThunk";

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IExecutionManager.cs:64

  • This adds new public API surface to the cDAC abstractions (CodeKind.WrapperStub / CodeKind.ShuffleThunk). Per dotnet/runtime process, new public APIs require a linked approved API issue (api-approved) or the new surface needs to stay internal until approval is obtained.

@noahfalk noahfalk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment thread src/coreclr/vm/stubmgr.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants